#ifndef UTIL_FILE_H_
#define UTIL_FILE_H_

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string>
#include <errno.h>
#include <fcntl.h>

static inline
bool file_exists(const std::string &filename){
	struct stat st;
	return stat(filename.c_str(), &st) == 0;
}

static inline
bool is_dir(const std::string &filename){
	struct stat st;
	if(stat(filename.c_str(), &st) == -1){
		return false;
	}
	return (bool)S_ISDIR(st.st_mode);
}

static inline
bool is_file(const std::string &filename){
	struct stat st;
	if(stat(filename.c_str(), &st) == -1){
		return false;
	}
	return (bool)S_ISREG(st.st_mode);
}

static inline
int dir_deep(const char *dir_path){
    int path_len = strlen(dir_path);
    int i, deep = 0;
    for(i = 1; i < path_len; i++){
        if(dir_path[i] == '/')
            deep ++;
    }
    return deep;
}

// return number of bytes read
static inline
int file_get_contents(const std::string &filename, std::string *content){
	char buf[8192];
	FILE *fp = fopen(filename.c_str(), "rb");
	if(!fp){
		return -1;
	}
	int ret = 0;
	while(!feof(fp) && !ferror(fp)){
		int n = fread(buf, 1, sizeof(buf), fp);
		if(n > 0){
			ret += n;
			content->append(buf, n);
		}
	}
	fclose(fp);
	return ret;
}

// return number of bytes written
static inline
int file_put_contents(const std::string &filename, const std::string &content){
	FILE *fp = fopen(filename.c_str(), "wb");
	if(!fp){
		return -1;
	}
	int ret = fwrite(content.data(), 1, content.size(), fp);
	fclose(fp);
	return ret == (int)content.size()? ret : -1;
}

static inline //如果没有此行 编译时会提示multiple definition of `dir_deep(char const*)'
bool is_ip(const char *host){
    int dot_count = 0;
    int digit_count = 0;
    for(const char *p = host; *p; p++){
        if(*p == '.'){
                dot_count += 1;
                if(digit_count >= 1 && digit_count <= 3){ 
                        digit_count = 0;
                }else{
                        return false;
                }   
        }else if(*p >= '0' && *p <= '9'){
                digit_count += 1;
        }else{
                return false;
        }
    }   
    return dot_count == 3;
}

static inline
int path_mod(const std::string path){
    struct stat buf;
    if(lstat(path.c_str(), &buf) == -1){
        return 0;
    }
    int n;
    int u = 0;
    int g = 0;
    int e = 0;
    for(n = 8; n >=0; n--){
        if( buf.st_mode & (1 << n) ){
            switch( n % 3 ){
                case 2://r
                    if(n >= 6 && n <= 8){
                        u += 4;
                    }else if(n >= 3 && n <= 5 ){
                        g += 4;
                    }else{
                        e += 4;
                    }
                    break;
                case 1://w
                    if(n >= 6 && n <= 8){
                        u += 2;
                    }else if(n >= 3 && n <= 5 ){
                        g += 2;
                    }else{
                        e += 2;
                    }
                    break;
                case 0://x
                    if(n >= 6 && n <= 8){
                        u += 1;
                    }else if(n >= 3 && n <= 5 ){
                        g += 1;
                    }else{
                        e += 1;
                    }
                    break;
                default:
                    break;
            }
        }else{
        
        }
    }
    char mod[4];
    memset(mod, '\0', sizeof(mod));
    sprintf(mod, "%d%d%d", u, g, e);    
    return atoi(mod);
}

static inline
int setnoblocking(int fd){
    int old_option = fcntl(fd, F_GETFL);
    int new_option = old_option | O_NONBLOCK;
    fcntl(fd, F_SETFL, new_option);
    return old_option;
}

#endif